package com.derbysoft.dswitch.adapter.ihg.dswitch3.service.impl;

import com.derbysoft.dswitch.adapter.ihg.common.log.LogBody;
import com.derbysoft.dswitch.adapter.ihg.common.log.PerformanceLogger;
import com.derbysoft.dswitch.adapter.ihg.common.utils.EnvironmentUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.HotelProviderService;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.Translator;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl.BaseTranslator;
import com.derbysoft.dswitch.adapter.ihg.exception.InvokeProviderSideException;
import com.derbysoft.dswitch.adapter.ihg.dto.Errors;
import com.derbysoft.dswitch.adapter.ihg.dto.OTAHotelAvailRQ;
import com.derbysoft.dswitch.adapter.ihg.dto.OTAHotelAvailRS;
import com.derbysoft.dswitch.adapter.ihg.webservice.handler.WebServiceHandler;
import com.derbysoft.dswitch.adapter.ihg.webservice.impl.AccountProvider;
import com.derbysoft.dswitch.dto.common.KeyValue;
import com.derbysoft.dswitch.dto.hotel.avail.HotelAvailRS;
import com.derbysoft.dswitch.dto.hotel.avail.HotelAvailRoomStayDTO;
import com.derbysoft.dswitch.remote.hotel.dto.ErrorDTO;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailRequest;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.ArrayList;

/**
 * Created by: jason
 * Date: 2012-5-8
 */
@Service("hotelAvailabilityService")
public class HotelAvailabilityServiceImpl extends BaseHotelService
        implements HotelProviderService<HotelAvailRequest, HotelAvailResponse> {

    @Autowired
    @Qualifier("hotelAvailRQTranslator")
    private Translator<HotelAvailRequest, OTAHotelAvailRQ, Void> hotelAvailRQTranslator;

    @Autowired
    @Qualifier("hotelAvailRSTranslator")
    private Translator<OTAHotelAvailRS, HotelAvailResponse, HotelAvailRequest> hotelAvailRSTranslator;

    @Autowired
    @Qualifier("availWebServiceHandler")
    private WebServiceHandler<OTAHotelAvailRQ, OTAHotelAvailRS> hotelAvailWebService;


    @Override
    public HotelAvailResponse invoke(HotelAvailRequest request) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            OTAHotelAvailRQ otaHotelAvailRQ = hotelAvailRQTranslator.translate(request, null);
            OTAHotelAvailRS otaHotelAvailRS = hotelAvailWebService.invoke(otaHotelAvailRQ, false,
                    AccountProvider.of(EnvironmentUtils.getGlobalIhgAvailabilityUrl(), loadAuthorization(request.getHeader().getSource())));
            stopWatch.stop();
            long webserviceTime = stopWatch.getTotalTimeMillis();
            if (otaHotelAvailRS.getErrors() != null) {
                return createFailedResponse(request, otaHotelAvailRS, webserviceTime);
            }
            HotelAvailResponse hotelAvailResponse = hotelAvailRSTranslator.translate(otaHotelAvailRS, request);
            hotelAvailResponse.getElapsedTimes().add(new KeyValue(ElapsedTimeType.AVAIL.name(), String.valueOf(webserviceTime)));
            return hotelAvailResponse;
        } catch (Exception ex) {
            if (stopWatch.isRunning()) {
                stopWatch.stop();
            }
            String webserviceTime = String.valueOf(stopWatch.getTotalTimeMillis());
            HotelAvailResponse failedResponse = createErrorResponse(request, ex);
            failedResponse.getElapsedTimes().add(new KeyValue(ElapsedTimeType.AVAIL.name(), webserviceTime));
            PerformanceLogger.append(LogBody.ERROR_CODE, failedResponse.getError().getCode());
            return failedResponse;
        }
    }

    private HotelAvailResponse createErrorResponse(HotelAvailRequest request, Exception ex) {
        HotelAvailResponse response = new HotelAvailResponse();
        response.setTaskId(request.getHeader().getTaskId());
        ErrorDTO errorDTO = new ErrorDTO();
        errorDTO.setCode(SYSTEM);
        errorDTO.setSource(ex instanceof InvokeProviderSideException ? provider : adapter);
        errorDTO.setMessage(ex.getMessage());
        response.setError(errorDTO);
        return response;
    }

    private HotelAvailResponse createFailedResponse(HotelAvailRequest request, OTAHotelAvailRS otaHotelAvailRS, long webserviceTime) {
        if (otaHotelAvailRS.getErrors().getError().get(0).getShortText().contains(BaseTranslator.NO_AVAIL_TEXT)) {
            return noAvailResponse(request, webserviceTime);
        }
        HotelAvailResponse response = new HotelAvailResponse();
        response.setTaskId(request.getHeader().getTaskId());
        response.getElapsedTimes().add(new KeyValue(ElapsedTimeType.AVAIL.name(), String.valueOf(webserviceTime)));
        Errors errors = otaHotelAvailRS.getErrors();
        response.setError(createError(errors));
        return response;
    }

    private HotelAvailResponse noAvailResponse(HotelAvailRequest request, long webserviceTime) {
        HotelAvailResponse noAvailResponse = new HotelAvailResponse();
        noAvailResponse.setTaskId(request.getHeader().getTaskId());
        noAvailResponse.getElapsedTimes().add(new KeyValue(ElapsedTimeType.AVAIL.name(), String.valueOf(webserviceTime)));
        HotelAvailRS hotelAvailRS = new HotelAvailRS();
        hotelAvailRS.setNoAvailHotelsList(request.getHotelAvailRQ().getAvailCriteria().getHotelCodesList());
        hotelAvailRS.setHotelAvailRoomStaysList(new ArrayList<HotelAvailRoomStayDTO>());
        noAvailResponse.setHotelAvailRS(hotelAvailRS);
        return noAvailResponse;
    }
}
